let time = ref 0.


let update =
    let start = Unix.gettimeofday () in
    begin
	print_endline (string_of_float !time);
	time := (Unix.gettimeofday () -. start)
    end


let myPoints = ref ((-1,-1,-1)::[])
let myFaces = ref ((-1,-1,-1)::[])
let myPositions = ref ((0.,0.,0.)::[])


let decompose line =
    let x = ref "" and y = ref "" and z = ref "" and number = ref 0 and tmp = ref line in
    begin
	tmp := String.sub !tmp 2 ((String.length !tmp) - 2);
	for i=0 to (String.index (!tmp) ' ') do
	    x := !x ^ (String.make 1 (String.get !tmp i));
	    number := i;
	done;


	tmp := String.sub !tmp (!number + 1) ((String.length !tmp) - !number - 1);
	for j=0 to (String.index (!tmp) ' ') do
	    y := !y ^ (String.make 1 (String.get !tmp j));
	    number := j;
	done;


	tmp := String.sub !tmp (!number + 1) ((String.length !tmp) - !number - 1);
	for k=0 to (String.length !tmp) - 1 do
	    z := !z ^ (String.make 1 (String.get !tmp k));
	    number := k;
	done;
    end;
    (!x,!y,!z)

(*
let readFile =
    let chan = open_in "test.obj" in
    try
	while true do
	    print_endline (input_line chan);
	done
    with End_of_file ->
	()
*)



let readFile =
    let current = ref "" in
    let chan = open_in "test3.obj" in
	try
	    while true do
		current := (input_line chan);
		print_endline "OOO";
		    if (String.get (!current) 0 == 'v') then
			let (x,y,z) = decompose (!current) in
			myPoints := ((int_of_string (String.sub x 0 ((String.length x) - 1))),
			(int_of_string (String.sub y 0 ((String.length y) - 1))),
			(int_of_string z)) :: !myPoints;

			print_endline ("point : +-+" ^ x ^ "+-+" ^ y ^ "+-+" ^ z ^ "+-+"); 
		    else if (String.get (!current) 0 == 'f') then
			    let (x,y,z) = decompose (!current) in
			    myFaces := (int_of_string (String.sub x 0 ((String.length x) - 1)), int_of_string (String.sub y 0 ((String.length y) - 1)),int_of_string z) :: !myFaces;
			    print_endline ("face : +-+" ^ x ^ "+-+" ^ y ^ "+-+" ^ z ^ "+-+")
		    else
			print_endline "none";
	    done;
	    myPoints := List.rev !myPoints;

	    []
	with End_of_file ->
	    close_in chan;
	    []

let id = ref 0


let clear () = 
  GlClear.clear  [`color; `depth]



let ouverture (x,y) =
  let _ = Glut.init Sys.argv in
  Glut.initWindowSize x y;
  Glut.createWindow "3D"

let fermeture i =
  Glut.destroyWindow i


(*
  draw_tri ((x1,y1,z1),(x2,y2,z2),(x3,y3,z3))
  prend en arg un triplet de triplet de float et affiche le triangle dont les trois sommets sont nos second triplet
*)
let draw_tri ((x1,y1,z1),(x2,y2,z2),(x3,y3,z3)) ((r1,g1,b1),(r2,g2,b2),(r3,g3,b3)) =
  GlDraw.begins `line_strip; (* `triangles affiche les surfaces
			       pleines; `line_strip affiche en
			       grillage *)

     GlDraw.color (r1, g1, b1);
    GlDraw.vertex3 (x1,y1,z1);
     GlDraw.color (r2, g2, b2);
    GlDraw.vertex3 (x3,y3,z3);
     GlDraw.color (r3, g3, b3);
    GlDraw.vertex3 (x2,y2,z2);
    GlDraw.ends()



let scale = 50.

let maxX = ref 0.
let maxY = ref 0.

let drawMap xxx =
    print_endline (">>> " ^ string_of_int(List.length !myPoints));
    
    for i=0 to (List.length !myFaces) - 2 do
    begin
	let (x,y,z) = List.nth !myFaces i in
	    begin
	    let (a,b,c) = (List.nth !myPoints x)
	    and (d,e,f) = (List.nth !myPoints y)
	    and (g,h,i) = (List.nth !myPoints z)
	    in
	    let (r1,g1,b1) = (List.nth !myPositions x)
	    and (r2,g2,b2) = (List.nth !myPositions y)
	    and (r3,g3,b3) = (List.nth !myPositions z)
	    in
	    draw_tri (((float)(a)/.scale,(float)(b)/.scale,(float)(c)/.scale),((float)d/.scale,(float)e/.scale,(float)f/.scale),((float)g/.scale,(float)h/.scale,(float)i/.scale)) ((r1,g1,b1),(r2,g2,b2),(r3,g3,b3));
	(***	print_endline ("> " ^ string_of_int(x) ^ "  -  " ^ string_of_int(a) ^ " - " ^ string_of_int(b) ^ " - " ^ string_of_int(c))***)
	    end
    end
    done
    


(*
  draw_list_tri l
  prend en parametre une liste de triplet de triplet de float et affiche chacun des arguments cf. draw_tri
*)
let rec draw_list_tri = function
  |[] -> ()
  |e::l -> let _ = draw_tri e in draw_list_tri l






(* Partie camera
****************************************************)

(* Variable de position de la camera *)
let campos_x = ref 10.
let campos_y = ref 10.
let campos_z = ref (8.)

(*Variable du point ou la camera regarde *)
let lokpos_x = ref 0.
let lokpos_y = ref (50.)
let lokpos_z = ref 0.

(* Variable de l'angle du haut *)
let updir_x = ref 0. 
let updir_y = ref 0.
let updir_z = ref 1.

(* Variable du vecteur directionnel *)
let vectdir_x = ref 0.
let vectdir_y = ref 1.
let vectdir_z = ref 0.
let phi = ref (!time *. 3.14159265 /. 2.)
let theta = ref (-3.14159265 /. 2.)





(* Passage des coord polaires au coord vect avec une distance de 1*)
let vect3_of_pol (t,p) = 
    (sin(p)*.cos(t),cos(p),(-1.)*.sin(p)*.sin(t))


(* Update des variables de position *)
let updtpos () =
  let (x,y,z) = vect3_of_pol (!theta, !phi) in
  vectdir_x := x;
  vectdir_y := y;
  vectdir_z := z
  (*lokpos_x := !campos_x +. !vectdir_x;
  lokpos_y := !campos_y +. !vectdir_y;
  lokpos_z := !campos_z +. !vectdir_z*)

let adddir () =
  campos_x := !campos_x +. (1.5 *. !vectdir_x);
  campos_y := !campos_y +. (1.5 *. !vectdir_y);
  campos_z := !campos_z +. (1.5 *. !vectdir_z)


let sousdir () =
  campos_x := !campos_x -. (1.5 *. !vectdir_x);
  campos_y := !campos_y -. (1.5 *. !vectdir_y);
  campos_z := !campos_z -. (1.5 *. !vectdir_z)


(* Fonction de test : marche 
affiche les coord du vecteur direction *)
let aff () =
    print_endline ((string_of_float(!vectdir_x)) ^ " " ^ (string_of_float(!vectdir_y)) ^ " " ^ (string_of_float(!vectdir_z)))


(* Fonction de test : marche 
affiche les coord du vecteur position *)
let affichposi () =
    print_endline ((string_of_float(!lokpos_x)) ^ " " ^ (string_of_float(!lokpos_y)) ^ " " ^ (string_of_float(!lokpos_z)))

let affichpos () =
    aff();
    affichposi()

(* Declaration de la camera *)
let cam () =
  updtpos();
  GluMat.look_at ~eye:(!campos_x,!campos_y,!campos_z) ~center:(!lokpos_x,!lokpos_y,!lokpos_z) ~up:(!updir_x,!updir_y,!updir_z)









(* Gestion du clavier
 *********************************************)

let clav () =
  Glut.keyboardFunc ~cb:(fun ~key ~x ~y -> match key with
			     (* Gestion de mes touches de
				base avec un matching *)
			   |13|32|27 -> fermeture !id
			   |54 -> theta := !theta +. 0.15
			   |52 -> theta := !theta -. 0.15
			   |56 -> phi := !phi -. 0.15
			   |50 -> phi := !phi +. 0.15
			   |_ -> print_endline ("merci d'utiliser les chiffres ou les fleches"));
  Glut.specialFunc ~cb:(fun ~key ~x ~y -> match Glut.string_of_special(key) with
			  (* Gestion de l'avance et du recul *)
			  |"KEY_UP" -> adddir ();
			  |"KEY_DOWN" -> sousdir ();
			  (* Gestion du vecteur directionnel *) 
			  | "KEY_PAGE_UP" -> campos_z := !campos_z -. 2.
			  | "KEY_PAGE_DOWN" -> campos_z := !campos_z +. 2.
			  |"KEY_RIGHT" -> campos_x := !campos_x +. 2.
			  |"KEY_LEFT" -> campos_x := !campos_x -. 2.
			  | "KEY_F1" -> Gl.enable `light1
			  |_ -> ()

)




(* Fonction d'affichage *)
let affich () =
  clear();
  GlMat.mode `projection;
  GlMat.load_identity ();
  GluMat.perspective ~fovy:90. ~aspect:(1.) ~z:(0.1,1000.);
  cam();
    (*Gl.enable `lighting;
    Gl.enable `light0;

    GlLight.light ~num:0 (`ambient (1.0,1.0,1.0,1.0));
    GlLight.light ~num:0 (`position ((0.0),5.0,(-10.0),2.0));
    Gl.enable `lighting;


    GlLight.light ~num:1 (`ambient (-1.0,-1.0,-1.0,-1.0));
    GlLight.light ~num:1 (`position ((0.0),-5.0,(10.0),-2.0));
*)
  GlMat.mode `modelview;
  GlMat.load_identity ()


(* Fonction de dessin *)
let draw () =
  clear();
  GlMat.mode `modelview;
  GlMat.load_identity ();


    drawMap 4;

  Gl.flush ();
  Gl.disable `depth_test;
  Glut.swapBuffers ();
  affich() (* On rappelle la fonction d'affichage pour mettre a jour la position de la camera *) 


(* fonction d'affichage rappele a chaque tour de boucle de mainLoop *)
let reshape ~w ~h =
  affich()

(* fonction de dessin rappele a chaque tour de boucle par mainLoop *)
let display () = 
    draw()


let readPositions =
    Sdl.init [`EVERYTHING];
    let (a,b,c) = (List.nth !myPoints (0)) in
	begin
	        maxX := float_of_int a;
	        maxY := float_of_int b;
	end;
    let img = Sdlloader.load_image Sys.argv.(1) in
    let (w,h) = ((Sdlvideo.surface_info img).Sdlvideo.w, (Sdlvideo.surface_info img).Sdlvideo.h) in
    begin
    for i=0 to (List.length !myPoints) - 2 do
	    let (x,y,_) = List.nth !myPoints i in
	    let (coorX,coorY) = ((float_of_int x) /. !maxX, (float_of_int y) /. !maxY)
	    in
	    begin
		let (r,g,b) = Sdlvideo.get_pixel_color img (int_of_float (coorX *. (float_of_int w))) (int_of_float (coorY *. (float_of_int h))) in
		(*myPositions := ((float)r,(float)g,(float)b)::(!myPositions);*)
		myPositions := List.append !myPositions [((float)r,(float)g,(float)b)];
		print_endline (string_of_float !maxX)
	    end

    done
    end



let main () =
  id := ouverture (1300,1000);
  readFile;

 readPositions;

  GlDraw.color (255.,255.,255.);
  clear();

  GlMat.mode `projection;
  GlMat.load_identity ();
  GlDraw.cull_face `both;
  affich();
  draw();

    Glut.reshapeFunc ~cb:reshape;(*appel de ma fonction d'affichage*)
  Glut.displayFunc ~cb:display;
  Glut.idleFunc ~cb:(Some Glut.postRedisplay);
  clav();

  update;

  Glut.mainLoop()


let _ =
  main ()

